----------------------------------------------------------------
-- PROCEDIMENTO que verifica a existência de uma pessoa
----------------------------------------------------------------
----------------------------------------------------------------
create or replace 
PROCEDURE f_verificar_pessoa(
  p_cpf         IN pessoa.cpf%TYPE,
  p_data        IN ingresso.data%TYPE,
  p_pes_existe  OUT NUMBER,
  p_esp_existe  OUT NUMBER,
  p_ing_existe  OUT NUMBER) AS
  
  CURSOR cur_pessoa IS SELECT pes.cpf pes_cpf, 
                                  esp.codigo esp_codigo,
                                  ing.data ing_data 
                                  FROM pessoa pes
                                  LEFT JOIN espectador esp ON pes.cpf = esp.cpf
                                  LEFT JOIN ingresso ing ON esp.cpf = ing.espectador
                                  WHERE pes.cpf = p_cpf;
  
  var_pessoa        cur_pessoa%ROWTYPE;

BEGIN
  p_pes_existe := 0;
  p_esp_existe := 0;
  p_ing_existe := 0;
  
  OPEN cur_pessoa;
  LOOP
    FETCH cur_pessoa INTO var_pessoa;
    EXIT WHEN cur_pessoa%NOTFOUND;
    IF p_pes_existe = 0 THEN
      p_pes_existe := 1;
    END IF;
    IF var_pessoa.esp_codigo IS NOT NULL THEN
      p_esp_existe := 1;
    END IF;
    IF TO_CHAR(var_pessoa.ing_data, 'dd/mm/yyyy') = TO_CHAR(p_data, 'dd/mm/yyyy') THEN
      p_ing_existe := 1;
    END IF;    
  END LOOP;
  CLOSE cur_pessoa; 
END f_verificar_pessoa;

\

----------------------------------------------------------------
-- PROCEDIMENTO que efetua o cadastro de uma pessoa no sistema.
----------------------------------------------------------------
----------------------------------------------------------------
create or replace 
PROCEDURE f_cadastrar_pessoa(
  p_cpf             IN pessoa.cpf%TYPE,
  p_nome            IN pessoa.nome%TYPE,
  p_data_nascimento IN pessoa.data_nascimento%TYPE,
  p_rua             IN pessoa.rua%TYPE,
  p_numero          IN pessoa.numero%TYPE,
  p_cidade          IN pessoa.cidade%TYPE,
  p_cep             IN pessoa.cep%TYPE,
  p_telefone        IN pessoa.telefone%TYPE,
  p_celular         IN pessoa.celular%TYPE,
  p_tipo            IN pessoa.tipo_pessoa%TYPE) AS
  
  var_cpf_valido    BOOLEAN;
  
  e_nulo            EXCEPTION;
  e_cpf_invalido    EXCEPTION;

BEGIN
 
  -- testando se existem valores nulos
  IF (p_cpf IS NULL) OR (p_nome IS NULL) OR (p_data_nascimento IS NULL) OR 
     (p_rua IS NULL) OR (p_numero IS NULL) OR (p_cidade IS NULL) OR 
     (p_cep IS NULL) OR (p_celular IS NULL) OR (p_tipo IS NULL) THEN
    RAISE e_nulo;
  END IF;  
  
  -- testando se o CPF fornecido é válido
  --validar_cpf(p_cpf, var_cpf_valido);
  --IF var_cpf_valido = FALSE THEN
  --  RAISE e_cpf_invalido;
  --END IF;
       
  INSERT INTO pessoa (cpf, nome, data_nascimento, rua, numero, cidade, cep, telefone, celular, tipo_pessoa) 
  VALUES (p_cpf, p_nome, p_data_nascimento, p_rua, p_numero, p_cidade, p_cep, p_telefone, p_celular, p_tipo);

  COMMIT;
  
  EXCEPTION
    WHEN e_nulo THEN
      raise_application_error (-20001, 'Os parâmetros cpf, nome, data_nascimento, rua, numero, cidade, cep, celular não podem assumir valores nulos.');
    WHEN DUP_VAL_ON_INDEX THEN
      raise_application_error (-20002, 'Você tentou cadastrar uma pessoa já existente.');
    WHEN e_cpf_invalido THEN
      raise_application_error (-20003, 'O CPF fornecido não é válido.');

END f_cadastrar_pessoa;

\

----------------------------------------------------------------
-- PROCEDIMENTO atribui ingressos a um espectador
----------------------------------------------------------------
----------------------------------------------------------------

create or replace 
PROCEDURE f_atribuir_ingresso(
  p_cpf             IN espectador.cpf%TYPE,
  p_data            IN ingresso.data%TYPE,
  p_valor           IN ingresso.valor%TYPE) AS
  
  var_cpf_valido    NUMBER;
  var_pes_existe    NUMBER;
  var_esp_existe    NUMBER;
  var_ing_existe    NUMBER;
  
  e_nulo            EXCEPTION;
  e_cpf_invalido    EXCEPTION;
  e_esp_existe      EXCEPTION;  
BEGIN
  
  -- testando se existem valores nulos
  IF (p_cpf IS NULL) OR (p_data IS NULL) OR (p_valor IS NULL) THEN
    RAISE e_nulo;
  END IF;  
  
  -- testando se o CPF fornecido é válido
  --validar_cpf(p_cpf, var_cpf_valido);
  --IF var_cpf_valido = 1 THEN
  --  RAISE e_cpf_invalido;
  --END IF;
  
  -- verifica espectador
  f_verificar_pessoa(p_cpf, p_data, var_pes_existe, var_esp_existe, var_ing_existe);
  -- se o ingresso para a data informada existe
  IF var_ing_existe = 1 THEN
    RAISE e_esp_existe;
  END IF;
  
  -- se ainda não há cadastro como espectador
  IF var_esp_existe = 0 THEN
      INSERT INTO espectador (cpf, codigo) VALUES (p_cpf, seq_espectador_cod.nextval);
  END IF;
  
  -- atribui ingresso ao espectador para a data escolhida
  INSERT INTO ingresso (numero, valor, data, hora_entrada, espectador) 
  VALUES (seq_ingresso_nro.nextval, p_valor, p_data, NULL, p_cpf);

  COMMIT;
  
  EXCEPTION
    WHEN e_nulo THEN
      raise_application_error (-20001, 'Os parâmetros cpf, data e valor não podem assumir valores nulos.');
    WHEN e_cpf_invalido THEN
      raise_application_error (-20003, 'O CPF fornecido não é válido.');      
    WHEN e_esp_existe THEN
      raise_application_error (-20004, 'Você tentou atribuir um ingresso para um espectador que já possui ingresso nesse dia.');
END f_atribuir_ingresso;

\

----------------------------------------------------------------
-- PROCEDIMENTO retorna as bandas de um show de uma line up.
----------------------------------------------------------------
----------------------------------------------------------------
create or replace 
PROCEDURE F_GET_BANDAS (
  p_data_line_up IN banda.data_line_up%TYPE,
  p_local IN banda.local%TYPE,
  cur_bandas OUT SYS_REFCURSOR
) AS
BEGIN
  OPEN cur_bandas FOR SELECT * FROM banda WHERE data_line_up = p_data_line_up AND local = p_local;
END F_GET_BANDAS;

\

----------------------------------------------------------------
-- PROCEDIMENTO retorna os integrantes de uma banda.
----------------------------------------------------------------
----------------------------------------------------------------
create or replace 
PROCEDURE F_GET_INTEGRANTES (
  p_banda IN integrante_banda.banda%TYPE,
  cur_integrantes OUT SYS_REFCURSOR
) AS
BEGIN
  OPEN cur_integrantes FOR SELECT * FROM integrante_banda WHERE banda = p_banda;
END F_GET_INTEGRANTES;

\

----------------------------------------------------------------
-- PROCEDIMENTO retorna as line ups do evento
----------------------------------------------------------------
----------------------------------------------------------------
create or replace 
PROCEDURE F_GET_LINE_UPS ( 
  cur_lineups OUT SYS_REFCURSOR
) AS
BEGIN
  OPEN cur_lineups FOR SELECT * FROM line_up;
END F_GET_LINE_UPS;

\

----------------------------------------------------------------
-- PROCEDIMENTO retorna os shows de uma line up.
----------------------------------------------------------------
----------------------------------------------------------------
create or replace 
PROCEDURE F_GET_SHOWS (
  p_data_line_up IN show.data_line_up%TYPE,
  cur_lineups OUT SYS_REFCURSOR
) AS
BEGIN
  OPEN cur_lineups FOR SELECT * FROM show WHERE data_line_up = p_data_line_up;
END F_GET_SHOWS;

\

----------------------------------------------------------------
-- PROCEDIMENTO de geração dos dados dos relatórios.
----------------------------------------------------------------
----------------------------------------------------------------
create or replace 
PROCEDURE f_relatar_ingressos(
  p_line_up             IN  VARCHAR2,
  p_num_tot             OUT NUMBER,
  p_num_com             OUT NUMBER,
  p_num_pre             OUT NUMBER,  
  p_porc_ven_usados     OUT VARCHAR2,
  p_porc_ven_nao_usados OUT VARCHAR2,
  p_porc_nao_ven        OUT VARCHAR2) AS

  CURSOR cur_ing IS SELECT ing.data, COUNT(ing.numero) num_comprados,
                  COUNT(CASE  WHEN TO_DATE(ing.hora_entrada, 'dd/mm/yyyy') IS NOT NULL THEN 1 END) num_presencas,
                  lu.capacidade num_total
                  FROM ingresso ing
                  LEFT JOIN espectador esp ON ing.espectador = esp.cpf
                  INNER JOIN line_up lu ON ing.data = lu.data
                  WHERE TO_CHAR(lu.data, 'dd/mm/yyyy') = p_line_up
                  GROUP BY ing.data, lu.capacidade;
  var_ing cur_ing%ROWTYPE;
  
BEGIN
  p_num_tot := 0;
  p_num_com := 0;
  p_num_pre := 0;
  OPEN cur_ing;
  LOOP
    FETCH cur_ing INTO var_ing;
    EXIT WHEN cur_ing%NOTFOUND;
      p_num_tot     := p_num_tot     + var_ing.num_total;
      p_num_com := p_num_com + var_ing.num_comprados;
      p_num_pre := p_num_pre + var_ing.num_presencas;
  END LOOP;
  CLOSE cur_ing;
  p_porc_ven_usados := TO_CHAR((p_num_pre/p_num_tot)*100,999.99) || '%'; 
  p_porc_ven_nao_usados := TO_CHAR(((p_num_com - p_num_pre)/p_num_tot)*100,999.99) || '%';
  p_porc_nao_ven := TO_CHAR(((p_num_tot - p_num_com)/p_num_tot)*100,999.99) || '%';
END f_relatar_ingressos;

\

----------------------------------------------------------------
-- PROCEDIMENTOS que acabaram por não ser utilizados no sistema
----------------------------------------------------------------

----------------------------------------------------------------
-- PROCEDIMENTO que verifica a disponibilidade de ingressos para
-- uma determinada line up
----------------------------------------------------------------
----------------------------------------------------------------
create or replace 
PROCEDURE verificar_disponibilidade(
  p_data            IN line_up.data%TYPE,
  var_num_ingressos OUT NUMBER) AS
  
  CURSOR cur_ingressos IS SELECT (capacidade - ingressos_vendidos) num_ingressos FROM line_up 
                          WHERE capacidade - ingressos_vendidos >= 1 
                          AND TO_DATE(data, 'dd/mm/yyyy') = TO_DATE(p_data, 'dd/mm/yyyy');
  
  var_ingressos cur_ingressos%ROWTYPE;

BEGIN
  -- Contando quantos ingressos estão disponíveis para a data em questão
  OPEN cur_ingressos;
  LOOP
    FETCH cur_ingressos INTO var_ingressos;
    EXIT WHEN cur_ingressos%NOTFOUND;
    var_num_ingressos := var_ingressos.num_ingressos;
  END LOOP;
  IF var_num_ingressos IS NULL THEN
    var_num_ingressos := 0;
  END IF;
  
  CLOSE cur_ingressos;
END verificar_disponibilidade;

\

----------------------------------------------------------------
-- PROCEDIMENTO que valida um cpf
----------------------------------------------------------------
----------------------------------------------------------------
create or replace 
PROCEDURE validar_cpf(
  p_cpf     IN pessoa.cpf%TYPE,
  p_valido  OUT BOOLEAN) AS
  
  var_verifica_dig  NUMBER;

BEGIN
  p_valido := FALSE;
 -- verificando tamanho
  IF (LENGTH(p_cpf) > 11) THEN 
    p_valido := FALSE;
    RETURN;
  END IF;
  -- calculando primeiro digito verificador
  var_verifica_dig := (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 1, 1)) * 10) + -- primeiro dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 2, 1)) * 9) + -- segundo dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 3, 1)) * 8) + -- terceiro dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 4, 1)) * 7) + -- quarto dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 5, 1)) * 6) + -- quinto dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 6, 1)) * 5) + -- sexto dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 7, 1)) * 4) + -- sétimo dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 8, 1)) * 3) + -- oitavo dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 9, 1)) * 2); -- nono dígito
  -- se o módulo da soma dos dígitos verificadores por 11 é menor que dois,
  -- o décimo digito, ou seja, o primeiro digito verificador deve ser 0
  IF MOD(var_verifica_dig,11) < 2 AND TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 10, 1)) <> 0 THEN
    p_valido := FALSE;
    RETURN;
  END IF;
  -- se o módulo da soma dos dígitos verificadores por 11 for maior que dois, 
  -- o décimo digito, ou seja, o primeiro digito verificador é o resultado de 11 menos o módulo
  IF MOD(var_verifica_dig,11) >= 2  AND TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 10, 1)) <> (11 - MOD(var_verifica_dig,11)) THEN
    p_valido := FALSE;
    RETURN;
  END IF;
  -- calculando o segundo dígito verificador
  var_verifica_dig := (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 1, 1)) * 11) + -- primeiro dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 2, 1)) * 10) + -- segundo dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 3, 1)) * 9) + -- terceiro dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 4, 1)) * 8) + -- quarto dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 5, 1)) * 7) + -- quinto dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 6, 1)) * 6) + -- sexto dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 7, 1)) * 5) + -- sétimo dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 8, 1)) * 4) + -- oitavo dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 9, 1)) * 3) + -- nono dígito
    (TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 10, 1)) * 2); -- décimo dígito
  -- se o módulo da soma dos dígitos verificadores por 11 é menor que dois,
  -- o décimo primeiro digito, ou seja, o segundo digito verificador deve ser 0
  IF MOD(var_verifica_dig,11) < 2 AND TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 11, 1)) <> 0 THEN
    p_valido := FALSE;
    RETURN;
  END IF;
  -- se o módulo da soma dos dígitos verificadores por 11 for maior que dois, 
  -- o décimo primeiro digito, ou seja, o segundo digito verificador é o resultado de 11 menos o módulo
  IF MOD(var_verifica_dig,11) >= 2  AND TO_NUMBER(SUBSTR(TRIM(TO_CHAR(p_cpf, '00000000000')), 11, 1)) <> (11 - MOD(var_verifica_dig,11)) THEN
    p_valido := FALSE;
    RETURN;
  END IF;
  p_valido := TRUE;
END validar_cpf;

\

----------------------------------------------------------------
-- PROCEDIMENTO que lista os blogs de um webmaster
----------------------------------------------------------------
----------------------------------------------------------------
create or replace 
PROCEDURE listar_webmaster_blogs(
  p_webmaster     IN webmaster.cpf%TYPE
  ) AS

  TYPE t_post IS RECORD (
    id                post.id%TYPE,
    data_hora_criacao post.data_hora_criacao%TYPE,
    texto             post.texto%TYPE
  );
  TYPE v_posts IS VARRAY(100) OF t_post;  

  TYPE t_blog IS RECORD (
    nome  blog.nome%TYPE,
    url   blog.url%TYPE,
    posts v_posts
  );
  TYPE v_blogs IS VARRAY(100) OF t_blog;  
  
  TYPE t_webmaster IS RECORD (
    nome  pessoa.nome%TYPE,
    email webmaster.email%TYPE,
    blogs v_blogs
  );
      
  CURSOR cur_wb IS SELECT pes.nome webmaster_nome,
                    wb.email webmaster_email,
                    bl.nome blog_nome,
                    bl.url blog_url,
                    pt.id post_id,
                    TO_DATE(pt.data_hora_criacao, 'dd/mm/yyyy HH24:MI') post_criacao,
                    pt.texto post_texto
                    FROM pessoa pes
                    INNER JOIN webmaster wb ON pes.cpf = wb.cpf
                    INNER JOIN post pt ON wb.cpf = pt.webmaster
                    INNER JOIN blog bl ON pt.blog = bl.url
                    WHERE pes.cpf = p_webmaster
                    ORDER BY blog_nome ASC, post_criacao DESC;
  var_wb cur_wb%ROWTYPE;
  
  var_webmaster   t_webmaster;
  var_blog_tmp    t_blog;
  var_post_tmp    t_post;
  
  var_control_wb  NUMBER;  
  var_num_blogs   NUMBER;
  var_num_posts   NUMBER;
BEGIN
  var_control_wb    := 0;
  var_num_blogs     := 0;
  var_num_posts     := 0;  
  var_blog_tmp.url  := 'u';
  var_post_tmp := NULL;
  
  OPEN cur_wb;
  LOOP
    FETCH cur_wb INTO var_wb;
    EXIT WHEN cur_wb%NOTFOUND;
    IF var_control_wb = 0 THEN
      var_webmaster.nome  := var_wb.webmaster_nome;
      var_webmaster.email := var_wb.webmaster_email;
      var_webmaster.blogs := NULL;
      var_control_wb := 1;
    END IF;
    -- se o blog atual é diferente do anterior
    --dbms_output.put_line('var_blog_tmp.url: ' || var_blog_tmp.url);
    --dbms_output.put_line('var_wb.blog_url: ' || var_wb.blog_url);
    IF var_blog_tmp.url <> var_wb.blog_url THEN
      -- se não foi lido nenhum blog
      --dbms_output.put_line('-- se não foi lido nenhum blog');
      IF var_num_blogs = 0 THEN
        --dbms_output.put_line('var_num_blogs = 0');
        var_num_blogs := 1;
      ELSE
        -- se o blog atual é o segundo, armazeno os dados do primeiro inicializando o vetor
        IF var_num_blogs = 1 THEN
          --dbms_output.put_line('-- se o blog atual é o segundo, armazeno os dados do primeiro inicializando o vetor');
          var_webmaster.blogs := v_blogs(var_blog_tmp);
        -- se o blog atual é o terceiro ou adiante, armazenando os dados do anterior adionando ao vetor
        ELSE
          --dbms_output.put_line('-- se o blog atual é o terceiro ou adiante, armazenando os dados do anterior adionando ao vetor');
          var_webmaster.blogs.extend;
          var_webmaster.blogs(var_num_blogs) := var_blog_tmp;
        END IF;
        var_num_blogs := var_num_blogs + 1;
      END IF;
      -- armazenando valores temporários do blog
      var_blog_tmp.nome := var_wb.blog_nome;
      var_blog_tmp.nome := var_wb.blog_url;
      -- armazenando valores temporários do post
      var_post_tmp.id                 := var_wb.post_id;
      var_post_tmp.data_hora_criacao  := var_wb.post_criacao;
      var_post_tmp.texto              := var_wb.post_texto;
      -- inicializando um novo vetor de posts
      var_num_posts      := 1;
      var_blog_tmp.posts := v_posts(var_post_tmp);
    -- se o blog atual é o mesmo do anterior
    ELSE
      -- armazenando valores temporários do post
      var_post_tmp.id                 := var_wb.post_id;
      var_post_tmp.data_hora_criacao  := var_wb.post_criacao;
      var_post_tmp.texto              := var_wb.post_texto;
      -- adicionando ao vetor de posts 
      var_num_posts      := var_num_posts + 1;
      var_blog_tmp.posts.extend;
      var_blog_tmp.posts(var_num_posts) := var_post_tmp;
    END IF;
  END LOOP;
  CLOSE cur_wb;
  -- leitura dos dados
  
  dbms_output.put_line('# Webmaster: ' || var_webmaster.nome || ' (' || var_webmaster.email || ')');
  dbms_output.put_line('');
  FOR i IN 1..var_webmaster.blogs.COUNT LOOP
    dbms_output.put_line('# Blog - ' || var_webmaster.blogs(i).nome || ' - ' || var_webmaster.blogs(i).url);
    FOR j IN 1..var_webmaster.blogs(i).posts.COUNT LOOP
      dbms_output.put_line('#---- Post id - ' || var_webmaster.blogs(i).posts(j).id);
      dbms_output.put_line('#---- Post data - ' || TO_CHAR(var_webmaster.blogs(i).posts(j).data_hora_criacao, 'dd/mm/yyyy HH24:MI'));
      dbms_output.put_line('#---- Post texto - ' || var_webmaster.blogs(i).posts(j).texto);
    END LOOP;
  END LOOP;
END listar_webmaster_blogs;

\

----------------------------------------------------------------
-- PROCEDIMENTO que lista os comentários de um post
----------------------------------------------------------------
----------------------------------------------------------------
create or replace 
PROCEDURE listar_comentarios(
  p_post        IN comentario.autor%TYPE,
  p_comentario  IN comentario.autor%TYPE,
  p_v_com_post  OUT v_comentarios,
  p_v_com_com   OUT v_comentarios
  ) AS  
  
  CURSOR cur_com_post       IS SELECT * FROM comentario WHERE idpost = p_post;
  CURSOR cur_com_comentario IS SELECT * FROM comentario WHERE idcomentario = p_comentario;
  
  var_com_post        cur_com_post%ROWTYPE;
  var_com_comentario  cur_com_comentario%ROWTYPE;
  
  var_comentario      t_comentario;
  var_num_comentarios NUMBER;
  
  e_nulo              EXCEPTION;
  
BEGIN
  -- verificando comentários de um post
  var_num_comentarios := 0;
  var_comentario      := NULL;
  
  IF p_post IS NULL AND p_comentario IS NULL THEN
    RAISE e_nulo;
  END IF;
  
  IF p_post IS NOT NULL THEN
    OPEN cur_com_post;
    LOOP
      FETCH cur_com_post INTO var_com_post;
      EXIT WHEN cur_com_post%NOTFOUND;
      var_comentario := t_comentario(
        var_com_post.id,
        var_com_post.autor,
        var_com_post.email,
        var_com_post.texto,
        var_com_post.data_hora_criacao,
        var_com_post.idpost,
        var_com_post.idcomentario
      );
      IF var_num_comentarios = 0 THEN
        var_num_comentarios := var_num_comentarios + 1;
        p_v_com_post := v_comentarios(var_comentario);
      ELSE
        var_num_comentarios := var_num_comentarios + 1;
        p_v_com_post.extend;
        p_v_com_post(var_num_comentarios) := var_comentario;
        END IF;      
    END LOOP;
    CLOSE cur_com_post;
  END IF;
  -- verificando comentários de um comentário
  var_num_comentarios  := 0;
  var_comentario      := NULL;
  IF p_comentario IS NOT NULL THEN
    OPEN cur_com_comentario;
    LOOP
      FETCH cur_com_comentario INTO var_com_comentario;
      EXIT WHEN cur_com_comentario%NOTFOUND;
      var_comentario := t_comentario(
        var_com_comentario.id,
        var_com_comentario.autor,
        var_com_comentario.email,
        var_com_comentario.texto,
        var_com_comentario.data_hora_criacao,
        var_com_comentario.idpost,
        var_com_comentario.idcomentario
      );
      IF var_num_comentarios = 0 THEN
        var_num_comentarios := var_num_comentarios + 1;
        p_v_com_com := v_comentarios(var_comentario);
      ELSE
        var_num_comentarios := var_num_comentarios + 1;
        p_v_com_com.extend;
        p_v_com_com(var_num_comentarios) := var_comentario;
        END IF;      
    END LOOP;
    CLOSE cur_com_comentario;
  END IF;

  EXCEPTION
    WHEN e_nulo THEN
      raise_application_error (-20001, 'Não existem post ou comentários para buscar comentários.');  

END listar_comentarios;
